package rct

import (
	"bytes"
	"net"
)

type BaseProtocol interface {
	Lock()
	UnLock()
	Init()
	ConnectionMade(sock *Socket)
	ConnectionClosed(sock *Socket)
	ConnectionRecved(sock *Socket, buffer *bytes.Buffer)
}

type Socket struct {
	Conn net.Conn
}

func (this *Socket) Init(conn net.Conn) {
	this.Conn = conn
}

func (this *Socket) Close() {
	if this.Conn != nil {
		this.Conn.Close()
		this.Conn = nil
	}
}

func (this *Socket) Write(data []byte) {
	if this.Conn != nil {
		this.Conn.Write(data)
	}
}

func (this *Socket) Register(proto BaseProtocol) {
	go this.netsloop(proto)
}

func (this *Socket) netsloop(proto BaseProtocol) {
	proto.Lock()
	proto.ConnectionMade(this)
	proto.UnLock()

	var recvbuf bytes.Buffer
	data := make([]byte, 5120)
	var n int
	var err error
	for {
		if this.Conn == nil {
			break
		}
		n, err = this.Conn.Read(data)
		if err != nil {
			break
		}
		recvbuf.Write(data[:n])
		proto.Lock()
		proto.ConnectionRecved(this, &recvbuf)
		proto.UnLock()
	}

	proto.Lock()
	proto.ConnectionClosed(this)
	proto.UnLock()
	if this.Conn != nil {
		this.Conn.Close()
	}
}

type Factory struct {
	listen     net.Listener
	CreateUser func() BaseProtocol
}

func (this *Factory) accept(listen net.Listener) {
	for {
		conn, err := listen.Accept()
		if err != nil {
			break
		}

		sock := new(Socket)
		sock.Init(conn)
		proto := this.CreateUser()
		proto.Init()
		sock.Register(proto)
	}
}

func (this *Factory) Listen(addr string) bool {
	listen, err := net.Listen("tcp", addr)
	if err != nil {
		return false
	}
	go this.accept(listen)
	this.listen = listen
	return true
}

func (this *Factory) Close() {
	this.listen.Close()
}

func Connect(proto BaseProtocol, network string, addr string) *Socket {
	conn, _ := net.Dial(network, addr)
	sock := new(Socket)
	sock.Init(conn)
	sock.Register(proto)
	return sock
}

func UdpConnect(proto BaseProtocol, addr string) *Socket {
	conn, _ := net.Dial("udp", addr)
	sock := new(Socket)
	sock.Init(conn)
	sock.Register(proto)
	return sock
}
